<template>
  <div>
    <div id="view-menu">
      <div class="icon-container">
        <span class="icon-span" title="布局">
          <span aria-label="node-index" class="anticon anticon-node-index" role="img" style="color: rgb(255, 255, 255)">
            <el-dropdown trigger="click" @command="updateLayout">
              <span class="el-dropdown-link">
                <i class="el-icon-sort" style="color: rgb(255, 255, 255)"></i>
              </span>
              <el-dropdown-menu slot="dropdown">
                <el-dropdown-item :command="'fruchterman'">FR算法布局</el-dropdown-item>
                <el-dropdown-item :command="'circular'">环形布局</el-dropdown-item>
                <el-dropdown-item :command="'force'">经典力导向布局</el-dropdown-item>
                <el-dropdown-item :command="'concentric'">同心圆布局</el-dropdown-item>
                <el-dropdown-item :command="'radial'">辐射状布局</el-dropdown-item>
                <el-dropdown-item :command="'mds'">高维数据降维算法布局</el-dropdown-item>
                <el-dropdown-item :command="'grid'">格子布局</el-dropdown-item>
              </el-dropdown-menu>
            </el-dropdown>
          </span>
        </span>
        <span class="icon-span" v-if="isVisble">
          <span style="color: rgb(255, 255, 255)">&nbsp;&nbsp;{{paginations.pageIndex}}&nbsp;&nbsp;</span>
          <el-button type="text" icon="el-icon-plus" title="继续加载" :disabled="isAble" @click="changePage('next')">
          </el-button>
        </span>
        <span class="icon-span">
          <el-button type="text" icon="el-icon-news" :disabled="isAble" title="保存" @click="Save"></el-button>
        </span>
        <span>
          <input type="text" id="search-node-input" @keyup.enter="searchNode()" />
          <button id="submit-button" @click="searchNode()">搜索</button>
        </span>
      </div>
    </div>
    <div id="container" v-loading="isLoading"></div>
    <el-dialog title="跳转图表" :visible.sync="dialogVisible" width="30%" :before-close="handleClose">
      <p>请复制以下</p>
      <el-input placeholder="请复制" v-model="input1" readonly>
        <!-- <el-button slot="append" icon="el-icon-document-copy">复制</el-button> -->
        <!-- <el-button slot="append" icon="el-icon-search"></el-button> -->
      </el-input>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="openNewblank">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
  import G6 from "@antv/g6";
  export default {
    props: {
      paginations: {
        type: Object,
        default: () => {},
      }
    },
    data() {
      return {
        graph: null,
        subNodeStyle: {
          fill: "#73e6ab",
          stroke: "#34ba76",
          lineWidth: 2,
        },
        attrNodeStyle: {
          fill: "#fc8af7",
          stroke: "#fe16fd",
          lineWidth: 2,
        },
        subNodeSelStyle: {
          fill: "#34ba76",
          stroke: "#34ba76",
          lineWidth: 2,
        },
        nodes: {}, //节点集合
        edges: {}, //边集合
        selNodes: [], //选择节点集合
        selAttrNodes: [], //选择属性节点集合
        isDbclickArr: [], //双击节点集合
        okBind: {},
        isLoading: false, //是否加载
        isDbclick: false,
        isAble: true,
        isVisble: true,

        dataGather: [], //数据集合
        dialogVisible: false,
        input1: "",
      };
    },
    mounted() {
      this.initView();
    },
    watch: {
      nodes: function (val) {
        if (JSON.stringify(val) == '{}') {
          this.isAble = true;
        } else {
          this.isAble = false;
        }
      },
    },
    methods: {
      //初始化视图
      initView() {
        if (JSON.stringify(this.paginations) == '{}') {
          this.isVisble = false;
        } else {
          this.isVisble = true;
        }
        const container = document.getElementById("container");
        const width = container.scrollWidth;
        const height = container.scrollHeight || 500;
        this.graph = new G6.Graph({
          container: "container",
          width,
          height,
          animate: true, // Boolean，切换布局时是否使用动画过度，默认为 false
          modes: {
            default: [
              "drag-canvas",
              "drag-node",
              "zoom-canvas",
              {
                type: "click-select",
                trigger: "ctrl",
                // 是否允许该 behavior 发生。若返回 false，被操作的 item 不会被选中，也不会触发 'nodeselectchange' 时机事件
                shouldBegin: (e) => {
                  console.log(e);
                  this.isDbclick = false;
                  return true;
                },
                shouldUpdate: (e) => {
                  if (
                    e.item._cfg.model.name === "Thing" ||
                    e.item._cfg.model.class == "attr"
                  )
                    return false;
                  return true;
                },
              },
            ],
            relation: [
              "drag-canvas",
              "zoom-canvas",
              "click-select",
              {
                type: "create-edge",
                trigger: "drag", // 'click' by default. options: 'drag', 'click'
                shouldBegin: (e) => {
                  // console.log(e);
                  if (
                    e.item._cfg.model.name === "Thing" ||
                    e.item._cfg.model.class == "attr"
                  )
                    return false;
                  return true;
                },
                shouldEnd: (e) => {
                  if (
                    e.item._cfg.model.name === "Thing" ||
                    e.item._cfg.model.class == "attr"
                  )
                    return false;
                  return true;
                },
              },
            ],
            edit: [
              "click-select",
              {
                type: "brush-select",
                // trigger: 'ctrl',
                includeEdges: false,
                // 是否允许对该 behavior 发生。若返回 false，被操作的 item 不会被选中，不触发 'nodeselectchange' 时机事件
                brushStyle: {
                  fill: "#3333ff",
                  fillOpacity: 0.2,
                  stroke: "#5e7cff",
                  lineWidth: 2,
                },
              },
            ],
          },
          layout: {
            type: "fruchterman",
            gravity: 5,
            speed: 5,
          },
          defaultNode: {
            type: "circle", // 节点类型
            size: 60,
            style: {
              fill: "#69bef7",
              stroke: "#017bff",
              lineWidth: 2,
            },
            labelCfg: {
              style: {
                fill: "#000",
              },
            },
          },
          defaultEdge: {
            type: "quadratic",
            labelCfg: {
              autoRotate: true,
              style: {
                fill: "#0000CD",
              },
            },
            style: {
              lineAppendWidth: 20,
              endArrow: {
                path: G6.Arrow.triangle(10, 10, 15), // 使用内置箭头路径函数，参数为箭头的 宽度、长度、偏移量（默认为 0，与 d 对应）
                d: 25,
              },
            },
          },
          nodeStateStyles: {
            selected: {
              fill: "#e6a23c",
              stroke: "#b58134",
              lineWidth: 2,
            },
            checked: {
              fill: "#e6a23c",
              stroke: "#b58134",
              lineWidth: 2,
            },
          },
          edgeStateStyles: {
            labelCfg: {
              style: {
                fill: "#0000CD",
              },
            },
            select: {
              fill: "#e6a23c",
              lineWidth: 2,
              shadowBlur: 10,
              shadowColor: "rgb(95, 149, 255)",
              stroke: "rgb(95, 149, 255)",
            },
          },
        });
        //绑定事件
        this.graph.on("node:dblclick", (ev) => {
          console.log(ev);
          this.isDbclick = true;
          if (this.isDbclickArr.indexOf(ev.item._cfg.id) < 0) {
            this.$store.dispatch("ajax", {
              url: `services/app-zonghe/api/example/g6_dataformat/relationships/things/_search`,
              method: "post",
              data: {
                where: {
                  bool_and: [{
                    bool_or: [{
                        "a.id.equals": Number(ev.item._cfg.id),
                      },
                      {
                        "b.id.equals": Number(ev.item._cfg.id),
                      },
                    ],
                  }, ],
                },
              },
              succeed: (res) => {
                console.log(res);
                if (res.data.length > 0) {
                  this.expand([ev.item.getModel()], ev, res.data);
                } else {
                  this.$message.error("暂无节点!");
                  return;
                }
              },
            });
          }
        });
        this.graph.on("nodeselectchange", (ev) => {
          console.log(ev);
          setTimeout(() => {
            if (this.isDbclick) {
              if (!select) {
                this.isDbclick = false;
                this.$emit("TouchWindow", false, null);
              }
              return;
            }
            const select = ev.select;
            if (select) {
              //判断多选还是单选
              //存在是单选
              if (ev.target) {
                this.$emit("TouchWindow", true, ev.target._cfg.model);
              }
              this.graph.setMode("edit"); //进入编辑模式
            } else {
              this.graph.setMode("default"); //进入默认模式
              this.$emit("TouchWindow", false, null);
              this.graph.render();
            }
            //选中状态
          }, 200);
        });
      },
      //初始加载数据
      loadTreeSub(data) {
        console.log(data);
        this.nodes = [];
        this.edges = [];
        this.selNodes = [];
        this.selAttrNodes = [];
        this.isDbclickArr = []; //清空已经炸开属性和子节点的节点集合
        this.graph.clear();
        this.isLoading = true;
        this.oneexpand(data);
      },
      //重新刷新
      refresh() {
        // this.graph.destroy();
        this.graph.clear();
        this.graph.render();
        // this.graph.data();
        // this.graph.paint();
        // this.graph.setAutoPaint(auto)
        this.nodes = [];
        this.edges = [];
        this.nodeId = [];
        this.isDbclickArr = []; //清空已经炸开属性和子节点的节点集合
      },
      //点击下一页
      changePage(type) {
        this.$emit('changePage', type, this.paginations.pageIndex)
      },
      //保存
      Save() {
        this.$store.dispatch("ajax", {
          url: "services/app-zonghe/api/knowledge/g6_dataformat/save/table",
          method: "post",
          data: {
            data: this.dataGather
          },
          succeed: (res) => {
            // console.log(res);
            this.dialogVisible = true;
            this.input1 = res.table;
          },
        });
      },
      handleClose(done) {
        this.$confirm('确认关闭？')
          .then(_ => {
            done();
          })
          .catch(_ => {});
      },
      //跳转到superlit
      openNewblank() {
        window.open('http://192.168.1.179:8088/chart/list/', '_blank');
      },
      //单机
      oneexpand(nodes, expandType = ["sub"]) {
        this.dataGather = this.dataGather.concat(nodes)
        for (const node of nodes) {
          console.log(node);
          if (expandType.includes("sub")) {
            const relations = node.relations;
            const attrInfo = node.attrs;
            let requireName = "";
            attrInfo.forEach((res) => {
              if (res.name == "名称") {
                requireName = res.value;
              }
            });
            console.log(relations);
            //没有关系
            if (relations.length == 0) {
              if (!this.nodes.hasOwnProperty(node.id)) {
                let addSubNode = node;
                addSubNode.id = node.id.toString();
                addSubNode.class = "subnode";
                addSubNode.name = node.id.toString();
                // addSubNode.label = node.id.toString();
                addSubNode.label = requireName;
                addSubNode.style = this.subNodeStyle;
                addSubNode.stateStyles = {
                  selected: this.subNodeSelStyle,
                  checked: this.subNodeSelStyle,
                };
                this.nodes[addSubNode.id] = addSubNode;
              }
            } else {
              //有关系
              if (!this.nodes.hasOwnProperty(node.id)) {
                let addSubNode = node;
                addSubNode.id = node.id.toString();
                addSubNode.class = "subnode";
                addSubNode.name = node.id.toString();
                // addSubNode.label = node.id.toString();
                addSubNode.label = requireName;
                addSubNode.style = this.subNodeStyle;
                addSubNode.stateStyles = {
                  selected: this.subNodeSelStyle,
                  checked: this.subNodeSelStyle,
                };
                this.nodes[addSubNode.id] = addSubNode;
              }
              relations.forEach((item) => {
                console.log(item);
                let relationName=item.name;
                const sourceNodeID = item.start_node;
                if (item.others.length > 0) {
                  for (let row of item.others) {
                    let targetNodeID = row.id;
                    let edgeId = `${item.id}_${row.id}`;
                    if (!this.edges.hasOwnProperty(edgeId)) {
                      this.edges[edgeId] = {
                        id: edgeId.toString(),
                        source: sourceNodeID.toString(),
                        target: targetNodeID.toString(),
                        name: relationName,
                        label: relationName,
                        class: "link",
                      };
                    }
                  }
                }
              });
            }
          }
        }
        this.isLoading = false;
        // this.graph.refresh();
        this.graph.data({
          nodes: Object.values(this.nodes),
          edges: Object.values(this.edges),
        });
        this.graph.render();
      },
      //双击 模型展开下一级的节点
      async expand(nodes, ev, newlist, expandType = ["sub"]) {
        console.log(nodes);
        console.log(ev);
        console.log(newlist);
        console.log(this.isDbclickArr);
        for (const node of newlist) {
          // console.log(node);
          if (expandType.includes("sub")) {
            const relations = node.relations;
            const attrInfo = node.attrs;
            let requireName = "";
            attrInfo.forEach((res) => {
              if (res.name == "名称") {
                requireName = res.value;
              }
            });
            // console.log(relations);
            if (relations.length == 0) {
              if (!this.nodes.hasOwnProperty(node.id)) {
                let addSubNode = JSON.parse(JSON.stringify(node));
                addSubNode.id = node.id.toString();
                addSubNode.class = "subnode";
                addSubNode.name = node.id.toString();
                // addSubNode.label = node.id.toString();
                addSubNode.label = requireName;
                addSubNode.style = this.subNodeStyle;
                addSubNode.stateStyles = {
                  selected: this.subNodeSelStyle,
                  checked: this.subNodeSelStyle,
                };
                this.nodes[addSubNode.id] = addSubNode;
                this.graph.addItem("node", addSubNode);
              }
            } else {
              //有关系
              if (!this.nodes.hasOwnProperty(node.id)) {
                let addSubNode = node;
                addSubNode.id = node.id.toString();
                addSubNode.class = "subnode";
                addSubNode.name = node.id.toString();
                // addSubNode.label = node.id.toString();
                addSubNode.label = requireName;
                addSubNode.style = this.subNodeStyle;
                addSubNode.stateStyles = {
                  selected: this.subNodeSelStyle,
                  checked: this.subNodeSelStyle,
                };
                this.nodes[addSubNode.id] = addSubNode;
                this.graph.addItem("node", addSubNode);
              }
              relations.forEach((item) => {
                const sourceNodeID = item.start_node;
                const targetNodeID = item.end_node;
                const edgeId = `${item.id}`;
                if (!this.edges.hasOwnProperty(edgeId)) {
                  this.edges[edgeId] = {
                    id: edgeId.toString(),
                    source: sourceNodeID.toString(),
                    target: targetNodeID.toString(),
                    name: item.name,
                    label: item.name,
                    class: "link",
                  };
                }
              });
            }
          }
        }
        console.log(this.nodes);
        //   this.graph.refresh();
        this.graph.data({
          nodes: Object.values(this.nodes),
          edges: Object.values(this.edges),
        });
        this.graph.render();
      },
      //切换布局
      updateLayout(type) {
        let layout = {};
        if (type == "fruchterman") {
          layout = {
            type: "fruchterman",
            gravity: 5,
            speed: 5,
          };
        } else if (type == "circular") {
          layout = {
            type: "circular",
            radius: 200,
          };
        } else if (type == "grid") {
          layout = {
            type: "grid",
          };
        } else if (type == "force") {
          layout = {
            type: "force",
            preventOverlap: true,
            nodeSize: 60,
            linkDistance: 150,
          };
        } else if (type == "radial") {
          layout = {
            type: "radial",
            preventOverlap: true,
            nodeSize: 60,
            linkDistance: 100,
          };
        } else if (type == "concentric") {
          layout = {
            type: "concentric",
            nodeSize: 60,
            minNodeSpacing: 100,
            preventOverlap: true,
          };
        } else if (type == "mds") {
          layout = {
            type: "mds",
            linkDistance: 250,
          };
        }

        this.graph.updateLayout(layout);
        this.graph.render();
      },
      //搜索当前节点
      searchNode() {
        const value = document.getElementById("search-node-input").value;
        const node = this.graph.find("node", (node) => {
          return node.get("model").label.includes(value);
        });
        if (node) {
          this.graph.focusItem(node, true);
          this.graph.setItemState(node, "selected", true);
        } else {
          this.$message.warning("没有找到该节点");
        }
      },
    },
  };
</script>

<style lang="scss" scoped>
  #container {
    width: 100%;
    height: 100%;
  }

  #view-menu {
    position: absolute;
    /*display: none;*/
    z-index: 2200;
    right: 15px;
    top: 0px;
    width: fit-content;
    padding: 8px 16px;
    background-color: rgba(54, 59, 64, 1);
    border-radius: 24px;
    box-shadow: 0 5px 18px 0 rgba(0, 0, 0, 0);
    font-family: PingFangSC-Semibold;
    transition: all 0.2s linear;
  }

  #view-menu:hover {
    background-color: rgba(54, 59, 64, 1);
    box-shadow: 0 5px 18px 0 rgba(0, 0, 0, 0.6);
  }

  .icon-span {
    padding-left: 8px;
    padding-right: 8px;
    cursor: pointer;
  }

  #search-node-input {
    background-color: rgba(60, 60, 60, 0.95);
    border-radius: 21px;
    width: 100px;
    border-color: rgba(80, 80, 80, 0.95);
    border-style: solid;
    color: rgba(255, 255, 255, 0.85);
  }

  #submit-button {
    background-color: rgba(82, 115, 224, 0.2);
    border-radius: 21px;
    border-color: rgb(82, 115, 224);
    border-style: solid;
    color: rgba(152, 165, 254, 1);
    margin-left: 4px;
  }
</style>